#include <Python.h>
#include <gtk/gtk.h>
#include "gtktester_search.h"
#include "gtktester_constants.h"
#include "gtktester_validations.h"
#include <gdk/gdkx.h>
#include "gtktester_lowlevel_x11.h"

void gtktester_yield_internal (void)
{
	while (g_main_context_iteration (NULL, FALSE));
}

static gboolean wait_callback (gpointer data)
{
	*((int*)data) = FALSE;
	return FALSE;
}

void gtktester_wait_internal (int wait)
{
	gboolean gtktester_waiting;
	guint timeout_id;
	gtktester_waiting = TRUE;
	timeout_id = g_timeout_add (wait, wait_callback, &gtktester_waiting);
	while (gtktester_waiting) {
		while (g_main_context_iteration (NULL, FALSE));
		/* Wait a jiff! */
	}
	return;
}

PyObject *gtktester_pressKey (PyObject *self, PyObject *args)
{
	char *key;
	gtktester_abort_if_not_string_arg (key);
	if (!lowlevel_pressKey (key)) {
		PyErr_Format(PyExc_KeyError, "Invalid KeySym '%s'", key);
		return(NULL);
	}
	
	gtktester_yield_internal();
	return Py_BuildValue("");
}

static PyObject *gtktester_click(PyObject *self, PyObject *args)
{
	const char *name;
	GtkWidget *widget;
	gint x, y, width, height;

	gtktester_abort_if_not_string_arg (name);
	widget = gtktester_find_widget_by_name (name);
	gtktester_abort_if_null (widget, name);
	gtktester_abort_if_not_button (widget, name);

	lowlevel_getWidgetGeometry (widget, &x, &y, &width, &height);

	lowlevel_movePointerTo (x + (width >> 1), y + (height >> 1));
	lowlevel_click (1);

	gtktester_wait_internal(100);
	return Py_BuildValue("");
}

PyObject *gtktester_movePointerTo (PyObject *self, PyObject *args)
{
	int dst_x, dst_y;
	gtktester_abort_if_not_two_int_args (dst_x, dst_y);
	printf("Moving to (%d,%d)\n", dst_x, dst_y);
	
	lowlevel_movePointerTo (dst_x, dst_y);
	return Py_BuildValue("");
}

static PyObject *gtktester_wait (PyObject *self, PyObject *args)
{
	int wait;
	gtktester_abort_if_not_int_arg (wait);
	gtktester_abort_if_negative (wait);
	gtktester_wait_internal (wait);
	gtktester_yield_internal();
	return Py_BuildValue("");
}

static PyObject *gtktester_yield(PyObject *self, PyObject *args)
{
	gtktester_abort_if_not_no_args;
	gtktester_yield_internal();
	return Py_BuildValue("");
}

static PyObject *gtktester_toggleButtonGetActive (PyObject *self, PyObject *args)
{
	const char *name;
	GtkWidget *widget;

	gtktester_abort_if_not_string_arg (name);
	widget = gtktester_find_widget_by_name (name);
	gtktester_abort_if_null (widget, name);
	gtktester_abort_if_not_toggle_button (widget, name);
	return Py_BuildValue("b", gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widget)));
}

static PyObject *gtktester_entryGetText (PyObject *self, PyObject *args)
{
	const char *name;
	GtkWidget *widget;
	gtktester_abort_if_not_string_arg (name);
	widget = gtktester_find_widget_by_name (name);
	gtktester_abort_if_null (widget, name);
	gtktester_abort_if_not_entry (widget, name);
	return Py_BuildValue("s", gtk_entry_get_text (GTK_ENTRY (widget)));
}

static PyMethodDef GtkTesterMethods[] = {
	{"click",  gtktester_click, METH_VARARGS, "Click on a button"},
	{"yield",  gtktester_yield, METH_VARARGS, "Process Gtk events for a short while"},
	{"wait",   gtktester_wait,  METH_VARARGS, "Process Gtk events for a certain amout of milliseconds"},
	{"pressKey",   gtktester_pressKey,  METH_VARARGS, "Press a key"},
	{"movePointerTo",   gtktester_movePointerTo,  METH_VARARGS, "Move the mouse pointer to a given location"},
	{"toggleButtonGetActive", gtktester_toggleButtonGetActive, METH_VARARGS, "Queries a GtkToggleButton and returns its current state"},
	{"entryGetText", gtktester_entryGetText, METH_VARARGS, "Retrieves the contents of the entry widget"},
	{NULL, NULL, 0, NULL}        /* Sentinel */
};

PyMODINIT_FUNC initgtktester(void)
{
	(void) Py_InitModule("gtktester", GtkTesterMethods);
}

